#ifndef VM_FRAME_H
#define VM_FRAME_H

#include <list.h>
#include <hash.h>
#include "devices/block.h"
#include "threads/synch.h"
#include <stdbool.h>
#include <stdint.h>

#define DISK 1
#define MEMORY 2
#define SWAP 3
#define MAP 4
#define STACK 5

/* Frame structure corresponds to exactly one frame, this can 
tell whether the frame is on swap, memory or disk. Contains other
important details such as length, block sector to read, user virtual
address and kernel virtual address
*/

struct frame_struct
{
  uint32_t flag;                          /* tells if on DISK/MEMORY/SWAP */
  uint8_t *upage;                         /* physical address */
  uint8_t *vaddr;                         /* virtual address in user memory */
  size_t page_length;                     /* for zero paging the rest of the
                                          bits after the page has been read */
  block_sector_t sector_number;           /* used for reading when the data is
                                          being loaded */
  struct lock frame_lock;                 /* so that the frame is not swapped
                                          out when swap occurs or the page is
                                          pinned */
  bool writable;                          /* to indicate the page being loaded
                                          is readonly or writable */
  struct list_elem elem;                  /* to maintain its position in 
                                          frame list */
};

/* Page struct corresponds to a virtual user page, makes up one supplementary unit
for the page table */
struct page_struct
{
  uint32_t key;                           /* key for the hash */
  struct frame_struct *fs;                /* pointer to the frame structure
                                          which is the value in the hash */
  struct hash_elem elem;                  /* used for hash operations */
};

void
supplementary_page_table_init (void);

struct page_struct *
supplementary_page_table_add (uint32_t *, uint8_t *, uint8_t *, size_t,
             uint32_t, block_sector_t, bool);

uint32_t * supplementary_page_table_find (uint32_t *, void *);

bool supplementary_page_table_delete (uint32_t *);

struct page_struct * supplementary_page_table_lookup (uint32_t *);

bool add_page (uint8_t *, uint8_t *, size_t, uint32_t, block_sector_t, bool);

struct page_struct * supplementary_page_table_page_struct_lookup (uint32_t *);

uint32_t * create_and_return_pde (void);

uint32_t * supplementary_page_table_page_entry_find (uint32_t *, const void *);

uint32_t * supplementary_page_table_page_entry_create (uint32_t *, const void *);

//function to organize and initialize the hash table
unsigned supplementary_page_table_hash_function (const struct hash_elem *, 
                                                 void * UNUSED);

//comparator function for hash elements
bool supplementary_page_table_comparator_function (const struct hash_elem *, 
                                                   const struct hash_elem *, 
                                                   void *aux);

uint8_t *
supplementary_page_table_frame_evict (void);
#endif 
